package com.geek.novel.services.manager

import android.os.Message
import android.os.Process
import com.geek.novel.common.BookDownloadEnum
import com.geek.novel.common.Constant
import com.geek.novel.entity.BookDownload
import com.geek.novel.entity.BookRead
import com.geek.novel.event.EventHandler
import com.geek.novel.event.EventObservable
import com.geek.novel.event.SimpleEventObservable
import com.geek.novel.services.BookDownloadRepository
import com.geek.novel.services.CrawlerRepository
import com.geek.novel.utils.LogCatUtil
import com.geek.novel.utils.ToastUtils
import java.util.concurrent.*


/**
 * 书籍全本缓存的管理器
 */
class BookDownloadManager private constructor(): SimpleEventObservable(), EventHandler, EventObservable {

    /**书籍缓存的数据库服务类*/
    private val bookDownloadRepository = BookDownloadRepository.getInstance()

    /**小说爬取接口*/
    private val crawlerRepository = CrawlerRepository.getInstance()

    /**保存书籍的缓存记录，防止重复进行任务*/
    private val bookDownloadMap = ConcurrentHashMap<String, BookDownloadThread>()

    companion object{
        @Volatile
        private var instance: BookDownloadManager? = null
        fun getInstance(): BookDownloadManager{
            if(instance == null){
                synchronized(BookDownloadManager::class.java){
                    if(instance == null){
                        instance = BookDownloadManager()
                    }
                }
            }
            return instance!!
        }
    }


    /**线程池*/
    private lateinit var executor: ThreadPoolExecutor

    init {
        /**初始化线程池*/
        this.initThreadPool()
    }


    /**线程的生成方式*/
    class PriorityThreadFactory(private val mThreadPriority: Int): ThreadFactory {
        override fun newThread(runnable: Runnable): Thread {
            val wrapperRunnable = Runnable {
                try {
                    Process.setThreadPriority(mThreadPriority)
                } catch (e: Throwable) {
                    LogCatUtil.e("???", e.message, e)
                }
                runnable.run()
            }
            return Thread(wrapperRunnable)
        }
    }

    /**初始化线程池*/
    private fun initThreadPool(){
        val corePoolSize = 1 // 线程池长期维持的线程数，即使线程处于Idle状态，也不会回收。
        val maximumPoolSize = 2 // 线程数的上限

        // 超过corePoolSize的线程的idle时长，超过这个时间，多余的线程会被回收。
        val keepAliveTime: Long = 10
        val unit = TimeUnit.SECONDS
        // 任务的排队队列
        val workQueue: BlockingQueue<Runnable> = ArrayBlockingQueue(100)
        // 新线程的产生方式
        val threadFactory: ThreadFactory = PriorityThreadFactory(Process.THREAD_PRIORITY_BACKGROUND)
        // 拒绝策略
        val handler: RejectedExecutionHandler = ThreadPoolExecutor.AbortPolicy() //超过就取消

        this.executor = ThreadPoolExecutor(
            corePoolSize,
            maximumPoolSize,
            keepAliveTime,
            unit,
            workQueue,
            threadFactory,
            handler
        )
    }

    /**开始缓存列表数据*/
    fun startDownloadList(){
        try {
            val list = bookDownloadRepository.findDownloadingBook()
            if(list.isEmpty()){
                return
            }
            for (bookDownload in list) {
                this.startDownload(bookDownload)
            }
        } catch (e: Exception) {
            LogCatUtil.e("???", e.message)
            ToastUtils.toast(e.message)
        }
    }


    /**缓存数据*/
    fun startDownload(book: BookRead, crawlerIndex: Int): Boolean{
        try {
            synchronized(BookDownloadManager::class.java){
                val bookId = book.bookId!!

                //获取书本的爬虫源
                val bookCrawler = crawlerRepository.getBookCrawler(book)
                val bookCrawlerId = bookCrawler.id
                if(bookCrawlerId == null){
                    ToastUtils.toast("爬取id为空！")
                    return false
                }
                var download = bookDownloadRepository.findByBookIdAndCrawlerId(bookId, bookCrawlerId)
                if(download == null){
                    download = BookDownload()
                    download.initEntity(bookId)
                    download.crawlerIndex = crawlerIndex
                    download.bookCrawlerId = bookCrawlerId
                    bookDownloadRepository.save(download)
                }
                this.startDownload(download)
                return true
            }
        } catch (e: Exception) {
            ToastUtils.toast("下载失败：${e.message}")
            LogCatUtil.e("???", e.message, e)
        }
        return false
    }


    /**入队开始缓存*/
    fun startDownload(bookDownload: BookDownload){
        if(BookDownloadEnum.DOWNLOADING.typeCode == bookDownload.status){
            throw RuntimeException("书籍正在缓存中,请稍候")
        }
        //暂停或未开始的任务，进入线程池
        if(BookDownloadEnum.DEFAULT.typeCode == bookDownload.status
            || BookDownloadEnum.PAUSE.typeCode == bookDownload.status
            || BookDownloadEnum.FINISH.typeCode == bookDownload.status){
            try {
                //修改任务为下载中
                bookDownload.status = BookDownloadEnum.DOWNLOADING.typeCode
                //保存实体
                bookDownloadRepository.save(bookDownload)

                //任务进入线程池开始处理
                this.startThread(bookDownload)

            } catch (e: Exception) {
                LogCatUtil.e("???", e.message, e)
            }
        }else{
            throw RuntimeException("书籍任务状态异常！code：${bookDownload.status}")
        }
    }


    /**
     * 下载线程缓存的key
     */
    private fun getDownloadCacheKey(bookDownload: BookDownload): String{
        return "${bookDownload.bookId}_${bookDownload.bookCrawlerId}"
    }

    /**开始处理任务进入线程池*/
    private fun startThread(bookDownload: BookDownload){
        //书籍id
        val cacheKey = this.getDownloadCacheKey(bookDownload)
        val cache = bookDownloadMap[cacheKey]
        if(cache != null){
            if(!cache.isStop()){
                LogCatUtil.i("???", "线程正在进行任务，跳过任务")
                ToastUtils.toast("请勿频繁操作缓存")
                return
            }
        }

        //创建线程
        val thread = BookDownloadThread(bookDownload, this)
        //加入集合，获取是否停止，停止状态的话可以反复停止
        bookDownloadMap[cacheKey] = thread

        this.executor.execute(thread)

    }

    /**停止任务*/
    fun stopTask(bookDownload: BookDownload){
        val cacheKey = this.getDownloadCacheKey(bookDownload)
        val cache = bookDownloadMap[cacheKey]
        if(cache != null){
            if(!cache.isStop()){
                cache.stop()
            }
        }
    }


    /**推送消息更新列表*/
    override fun handleMessage(msg: Message) {
        when(msg.what){
            //缓存书籍完成
            Constant.handler_event_book_download_update_success->{
                val bookDownload = msg.obj as BookDownload
                val cacheKey = this.getDownloadCacheKey(bookDownload)
                bookDownloadMap.remove(cacheKey)
            }
        }
        //通知观察者
        this.notifyEvent(msg)
    }

}
